#ifndef CNC_BASE_MILL_MEMORY_IMPLEMENTATION_H
#define CNC_BASE_MILL_MEMORY_IMPLEMENTATION_H

// provided interfaces
#include "taskctl.h"
#include "millgdata.h"
// required interfaces
#include "millpdata.h"
// basic component model
#include <bcm/bcm.h>
// used interface
#include "globaldata.h"
// include files
#include "milldatamodel.h"
#include "kbdcmdid.h"

namespace cnc {

	namespace base {

		class MillMemoryImpl : public bcm::Identifier<cnc::base::TaskControl>,
			public bcm::Identifier<MillGlobalData>
		{
		protected:
			bcm::GetComponentResult result_;
			GlobalData *gdata_;
			MillPersistentData *pdata_;
		protected:
			MillMemoryImpl() : bcm::Identifier<TaskControl>("taskctl", "Task Control"),
				bcm::Identifier<MillGlobalData>("millpdata", "Mill Persistent Data"),
				result_(bcm::GC_OK), pdata_(0)
			{
				gdata_ = 0;
				bcm::ComponentManager &compMgr = bcm::ComponentManager::instance();
				switch (compMgr.loadComponent(TEXT("memory.dll"))) {
				case bcm::LC_NODLL:
				case bcm::LC_NOCOMPONENT:
				case bcm::LC_ALREADYUSED:
					result_ = bcm::GC_INCOMPLETE;
					return;
				}
				bcm::Component *component;
				switch (compMgr.getComponent("mem", &component)) {
				case bcm::GC_UNREGISTERED:
				case bcm::GC_NOCOMPONENT:
				case bcm::GC_INCOMPLETE:
					result_ = bcm::GC_INCOMPLETE;
					return;
				}
				bcm::Interface *iface;
				iface = component->getInterface("gdata");
				if (iface == 0) {
					result_ = bcm::GC_INCOMPLETE;
					return;
				}
				gdata_ = dynamic_cast<GlobalData *>(iface);
				if (gdata_ == 0) {
					result_ = bcm::GC_INCOMPLETE;
					return;
				}
			}
			cnc::base::TaskControl *getTaskControl()
			{
				return static_cast<cnc::base::TaskControl *>(this);
			}
			GlobalData *getGlobalData()
			{
				return gdata_;
			}
			MillGlobalData *getMillGlobalData()
			{
				return static_cast<MillGlobalData *>(this);
			}
			void setMillPersistentData(MillPersistentData *pdata)
			{
				pdata_ = pdata;
			}
		protected: // TaskControl
			virtual bool start()
			{
				if (gdata_ == 0 || pdata_ == 0)
					return false;
				Register *reg;
				Parameter *param;
				gdata_->addRegister("machine operation::emergency stop", DT_INT8);
				reg = gdata_->getRegister("machine operation::emergency stop");
				reg->set(static_cast<int8_t>(cnc::comm::EMERGENCY::STOP));
				gdata_->addRegister("machine operation::operation mode", DT_INT8);
				reg = gdata_->getRegister("machine operation::operation mode");
				reg->set(static_cast<int8_t>(cnc::comm::MODE::HOME));
				gdata_->addRegister("path planning::motion type", DT_INT8);
				reg = gdata_->getRegister("path planning::motion type");
				reg->set(static_cast<int8_t>(MOTION_TYPE::MT_LINEAR));
				gdata_->addRegister("path planning::cartesian plane", DT_INT8);
				reg = gdata_->getRegister("path planning::cartesian plane");
				reg->set(static_cast<int8_t>(CARTESIAN_PLANE::CP_XY));
				gdata_->addRegister("path planning::metric system", DT_UINT8);
				reg = gdata_->getRegister("path planning::metric system");
				uint8_t defaultMetricSystem;
				param = pdata_->getParameter("path planning::default metric system");
				param->get(&defaultMetricSystem);
				reg->set(static_cast<int8_t>(defaultMetricSystem));
				gdata_->addRegister("path planning::dimensioning mode", DT_INT8);
				reg = gdata_->getRegister("path planning::dimensioning mode");
				int8_t defaultDimensioningMode;
				param = pdata_->getParameter("path planning::default dimensioning mode");
				param->get(&defaultDimensioningMode);
				reg->set(defaultDimensioningMode);
				gdata_->addRegister("path planning::x axis target position", DT_INT32);
				reg = gdata_->getRegister("path planning::x axis target position");
				reg->set(static_cast<int32_t>(0));
				gdata_->addRegister("path planning::y axis target position", DT_INT32);
				reg = gdata_->getRegister("path planning::y axis target position");
				reg->set(static_cast<int32_t>(0));
				gdata_->addRegister("path planning::z axis target position", DT_INT32);
				reg = gdata_->getRegister("path planning::z axis target position");
				reg->set(static_cast<int32_t>(0));
				gdata_->addRegister("path planning::active work offset index", DT_INT8);
				reg = gdata_->getRegister("path planning::active work offset index");
				reg->set(static_cast<int8_t>(0));
				gdata_->addRegister("path planning::active tool offset index", DT_INT8);
				reg = gdata_->getRegister("path planning::active tool offset index");
				reg->set(static_cast<int8_t>(0));
				gdata_->addRegister("axis motion::cutting mode", DT_INT8);
				reg = gdata_->getRegister("axis motion::cutting mode");
				reg->set(static_cast<int8_t>(CUTTING_MODE::CM_NORMAL));
				gdata_->addRegister("axis motion::cutting feedrate", DT_INT32);
				reg = gdata_->getRegister("axis motion::cutting feedrate");
				uint32_t defaultCuttingFeedrate;
				param = pdata_->getParameter("axis motion::default cutting feedrate");
				param->get(&defaultCuttingFeedrate);
				reg->set(defaultCuttingFeedrate);
				gdata_->addRegister("axis motion::cutting feedrate override", DT_INT8);
				reg = gdata_->getRegister("axis motion::cutting feedrate override");
				reg->set(static_cast<int8_t>(0));

				gdata_->addRegister("axis motion::jog feedrate", DT_UINT32);
				reg = gdata_->getRegister("axis motion::jog feedrate");
				uint32_t jogFeedrate;
				param = pdata_->getParameter("axis motion::jog feedrate");
				param->get(&jogFeedrate);
				reg->set(jogFeedrate);

				gdata_->addRegister("axis motion::jog feedrate override", DT_UINT8);
				reg = gdata_->getRegister("axis motion::jog feedrate override");
				reg->set(static_cast<uint8_t>(100));
				gdata_->addRegister("axis motion::rapid traverse rate override", DT_UINT8);
				reg = gdata_->getRegister("axis motion::rapid traverse rate override");
				reg->set(static_cast<uint8_t>(100));
				gdata_->addRegister("axis motion::jog x axis positive", DT_INT8);
				reg = gdata_->getRegister("axis motion::jog x axis positive");
				reg->set(static_cast<int8_t>(0));
				gdata_->addRegister("axis motion::jog x axis negative", DT_INT8);
				reg = gdata_->getRegister("axis motion::jog x axis negative");
				reg->set(static_cast<int8_t>(0));
				gdata_->addRegister("axis motion::jog y axis positive", DT_INT8);
				reg = gdata_->getRegister("axis motion::jog y axis positive");
				reg->set(static_cast<int8_t>(0));
				gdata_->addRegister("axis motion::jog y axis negative", DT_INT8);
				reg = gdata_->getRegister("axis motion::jog y axis negative");
				reg->set(static_cast<int8_t>(0));
				gdata_->addRegister("axis motion::jog z axis positive", DT_INT8);
				reg = gdata_->getRegister("axis motion::jog z axis positive");
				reg->set(static_cast<int8_t>(0));
				gdata_->addRegister("axis motion::jog z axis negative", DT_INT8);
				reg = gdata_->getRegister("axis motion::jog z axis negative");
				reg->set(static_cast<int8_t>(0));
				gdata_->addRegister("axis motion::handwheel factor", DT_INT8);
				reg = gdata_->getRegister("axis motion::handwheel factor");
				reg->set(static_cast<int8_t>(cnc::comm::HANDWHEEL::FACTOR_1));
				gdata_->addRegister("axis motion::handwheel axis", DT_INT8);
				reg = gdata_->getRegister("axis motion::handwheel axis");
				reg->set(static_cast<int8_t>(cnc::comm::HANDWHEEL::SELECT_AXIS_X));
				gdata_->addRegister("axis motion::homing high traverse rate", DT_INT32);
				reg = gdata_->getRegister("axis motion::homing high traverse rate");
				reg->set(static_cast<int32_t>(0));
				gdata_->addRegister("axis motion::homing low traverse rate", DT_INT32);
				reg = gdata_->getRegister("axis motion::homing low traverse rate");
				reg->set(static_cast<int32_t>(0));
				gdata_->addRegister("axis motion::x axis left soft limit switch", DT_INT8);
				reg = gdata_->getRegister("axis motion::x axis left soft limit switch");
				reg->set(static_cast<int8_t>(0));
				gdata_->addRegister("axis motion::x axis left hard limit switch", DT_INT8);
				reg = gdata_->getRegister("axis motion::x axis left hard limit switch");
				reg->set(static_cast<int8_t>(0));
				gdata_->addRegister("axis motion::x axis right soft limit switch", DT_INT8);
				reg = gdata_->getRegister("axis motion::x axis right soft limit switch");
				reg->set(static_cast<int8_t>(0));
				gdata_->addRegister("axis motion::x axis right hard limit switch", DT_INT8);
				reg = gdata_->getRegister("axis motion::x axis right hard limit switch");
				reg->set(static_cast<int8_t>(0));
				gdata_->addRegister("axis motion::y axis left soft limit switch", DT_INT8);
				reg = gdata_->getRegister("axis motion::y axis left soft limit switch");
				reg->set(static_cast<int8_t>(0));
				gdata_->addRegister("axis motion::y axis left hard limit switch", DT_INT8);
				reg = gdata_->getRegister("axis motion::y axis left hard limit switch");
				reg->set(static_cast<int8_t>(0));
				gdata_->addRegister("axis motion::y axis right soft limit switch", DT_INT8);
				reg = gdata_->getRegister("axis motion::y axis right soft limit switch");
				reg->set(static_cast<int8_t>(0));
				gdata_->addRegister("axis motion::y axis right hard limit switch", DT_INT8);
				reg = gdata_->getRegister("axis motion::y axis right hard limit switch");
				reg->set(static_cast<int8_t>(0));
				gdata_->addRegister("axis motion::z axis left soft limit switch", DT_INT8);
				reg = gdata_->getRegister("axis motion::z axis left soft limit switch");
				reg->set(static_cast<int8_t>(0));
				gdata_->addRegister("axis motion::z axis left hard limit switch", DT_INT8);
				reg = gdata_->getRegister("axis motion::z axis left hard limit switch");
				reg->set(static_cast<int8_t>(0));
				gdata_->addRegister("axis motion::z axis right soft limit switch", DT_INT8);
				reg = gdata_->getRegister("axis motion::z axis right soft limit switch");
				reg->set(static_cast<int8_t>(0));
				gdata_->addRegister("axis motion::z axis right hard limit switch", DT_INT8);
				reg = gdata_->getRegister("axis motion::z axis right hard limit switch");
				reg->set(static_cast<int8_t>(0));
				gdata_->addRegister("axis motion::x axis current position", DT_INT32);
				reg = gdata_->getRegister("axis motion::x axis current position");
				reg->set(static_cast<int32_t>(0));
				gdata_->addRegister("axis motion::y axis current position", DT_INT32);
				reg = gdata_->getRegister("axis motion::y axis current position");
				reg->set(static_cast<int32_t>(0));
				gdata_->addRegister("axis motion::z axis current position", DT_INT32);
				reg = gdata_->getRegister("axis motion::z axis current position");
				reg->set(static_cast<int32_t>(0));
				gdata_->addRegister("program execution::machining cycle status", DT_INT8);
				reg = gdata_->getRegister("program execution::machining cycle status");
				reg->set(static_cast<int8_t>(cnc::base::MACHINING_CYCLE_STATUS::MCS_FEEDHOLD));
				gdata_->addRegister("program execution::block execution", DT_INT8);
				reg = gdata_->getRegister("program execution::block execution");
				reg->set(static_cast<int8_t>(cnc::base::BLOCK_EXECUTION::BE_CONTINUOUS));
				gdata_->addRegister("program execution::optional stop", DT_INT8);
				reg = gdata_->getRegister("program execution::optional stop");
				reg->set(static_cast<int8_t>(cnc::base::OPTIONAL_STOP::OS_SKIP));
				gdata_->addRegister("program execution::block skip", DT_INT8);
				reg = gdata_->getRegister("program execution::block skip");
				reg->set(static_cast<int8_t>(cnc::base::BLOCK_SKIP::BS_READ));
				gdata_->addRegister("program execution::dry run", DT_INT8);
				reg = gdata_->getRegister("program execution::dry run");
				reg->set(static_cast<int8_t>(cnc::base::DRY_RUN::DR_NORMAL));
				gdata_->addRegister("program execution::mst lock", DT_INT8);
				reg = gdata_->getRegister("program execution::mst lock");
				reg->set(static_cast<int8_t>(cnc::base::MST_LOCK::ML_NORMAL));
				gdata_->addRegister("program execution::xy axes lock", DT_INT8);
				reg = gdata_->getRegister("program execution::xy axes lock");
				reg->set(static_cast<int8_t>(cnc::base::AXIS_LOCK::AL_NORMAL));
				gdata_->addRegister("program execution::z axis neglect", DT_INT8);
				reg = gdata_->getRegister("program execution::z axis neglect");
				reg->set(static_cast<int8_t>(cnc::base::AXIS_LOCK::AL_NORMAL));
				gdata_->addRegister("spindle::spindle direction", DT_INT8);
				reg = gdata_->getRegister("spindle::spindle direction");
				reg->set(static_cast<int8_t>(cnc::comm::SPINDLE::NORMAL_ROTATION));
				gdata_->addRegister("spindle::spindle motion", DT_INT8);
				reg = gdata_->getRegister("spindle::spindle motion");
				reg->set(static_cast<int8_t>(cnc::comm::SPINDLE::STOP));
				gdata_->addRegister("spindle::spindle speed override", DT_INT8);
				reg = gdata_->getRegister("spindle::spindle speed override");
				reg->set(static_cast<int8_t>(100));
				gdata_->addRegister("spindle::spindle speed", DT_INT16);
				reg = gdata_->getRegister("spindle::spindle speed");
				reg->set(static_cast<int16_t>(1500));
				gdata_->addRegister("atc::next tool index", DT_INT8);
				reg = gdata_->getRegister("atc::next tool index");
				reg->set(static_cast<int8_t>(0));
				gdata_->addRegister("device::light::device status", DT_INT8);
				reg = gdata_->getRegister("device::light::device status");
				reg->set(static_cast<int8_t>(cnc::comm::DEVICE::DISABLE<0>::ID));
				gdata_->addRegister("device::coolant::device status", DT_INT8);
				reg = gdata_->getRegister("device::coolant::device status");
				reg->set(static_cast<int8_t>(cnc::comm::DEVICE::DISABLE<1>::ID));
				return true;
			}
			virtual bool execute()
			{
				return true;
			}
			virtual bool stop()
			{
				return true;
			}
		protected: // MillGlobalData
			virtual Register *getRegister(const char *registerID)
			{
				if (gdata_ == 0)
					return 0;
				return gdata_->getRegister(registerID);
			}
			virtual bool addObserver(const char *registerID, Observer *observer)
			{
				return gdata_->addObserver(registerID, observer);
			}
			virtual bool removeObserver(const char *registerID, Observer *observer)
			{
				return gdata_->removeObserver(registerID, observer);
			}

		};

	} // namespace base

} // namespace cnc

#endif
